package com.shanghaionstar.login.service;

import android.content.Context;
import android.util.SparseArray;

import com.onstar.cn.api.OauthService;
import com.onstar.cn.api.util.AuthUtils;
import com.onstar.cn.auth.AuthPinTokenEntity;
import com.onstar.cn.auth.AuthTokenRequestEntity;
import com.onstar.cn.common.exception.HttpException;
import com.onstar.cn.common.exception.OnStarException;
import com.onstar.cn.common.log.LogManager;
import com.onstar.cn.common.util.CommonUtil;
import com.onstar.cn.common.util.Constants;
import com.onstar.cn.common.util.DeviceUtil;
import com.onstar.cn.common.util.PreferencesUtls;
import com.onstar.cn.framework.annotation.http.HeadsValue;
import com.onstar.cn.framework.annotation.http.Request;
import com.onstar.cn.framework.mvp.base.core.BaseService;
import com.onstar.cn.framework.network.HttpInjectUtils;
import com.onstar.cn.framework.network.entity.RequestEntity;
import com.onstar.cn.framework.network.enumtype.HttpAccept;
import com.onstar.cn.framework.network.enumtype.HttpMethod;
import com.onstar.cn.framework.network.enumtype.Language;
import com.onstar.cn.framework.network.http.CommonError;
import com.onstar.cn.framework.utils.ExceptionUtil;
import com.onstar.cn.framework.utils.GsonHelper;
import com.shanghaionstar.enumtype.FunctionNameFindId;
import com.shanghaionstar.report.bean.ReportReqParam;
import com.shanghaionstar.utils.ApplicationUtil;
import com.shanghaionstar.utils.AuthorUtil;
import com.shanghaionstar.utils.BusinessUtil;
import com.shanghaionstar.utils.FinalConfigParams;
import com.shanghaionstar.utils.NetConnectUtil;

import java.util.LinkedHashMap;

import rx.Observable;
import rx.functions.Func0;

/**
 * Created by 6335yz on 2016/6/29.
 */
public class AuthorService extends BaseService {
    @Override
    public RequestEntity getRequestEntity() {
        return null;
    }

    private LogManager log = LogManager.getInstance();

    private Context context;

    public AuthorService(Context context) {
        this.context = context;
    }

    @Override
    public Object jsonToBean(String json) {
        return null;
    }

    public Observable<AuthPinTokenEntity> pinReauthForNoPin(final AuthTokenRequestEntity entity) {
        return Observable.defer(new Func0<Observable<AuthPinTokenEntity>>() {
            @Override
            public Observable<AuthPinTokenEntity> call() {
                try {
                    return Observable.just(pinReauthenticationForNoPin(entity));
                } catch (OnStarException e) {
                    return Observable.error(e);
                }
            }
        });
    }

    @Request(heads = @HeadsValue(accept = HttpAccept.JSON, language = Language.AUTO), method = HttpMethod.POST)
    public AuthPinTokenEntity pinReauthenticationForNoPin(AuthTokenRequestEntity entity) throws OnStarException {
        boolean isSuccess = true;
        long startTimeStamp = System.currentTimeMillis();
        entity.setDeviceId(new DeviceUtil(context).getDeviceID());
        OauthService service = new OauthService(Constants.CURRENT_AUTH_URL);
        RequestEntity requestEntity = new RequestEntity();
        String idToken = PreferencesUtls.getInstance(context).getString(Constants.ID_TOKEN);
        try {
            requestEntity = service.reauthenticTokenForNOPinCommand(requestEntity, entity.getClientId(), idToken,
                    entity.getDeviceId(), entity.getClientSecret(), entity.getScope());
        } catch (Exception e) {
            if (entity.isAutoLogin()) {
                isSuccess = false;
                long endTimeStamp = System.currentTimeMillis();
                ReportReqParam reportReqParam = ReportReqParam.getLoginReqParm(isSuccess);
                reportReqParam.startTimestamp = startTimeStamp;
                reportReqParam.endTimestamp = endTimeStamp;
                reportReqParam.functionNameFindId = FunctionNameFindId.Login_GetToken.getStringValue();
                BusinessUtil.sendReportByRequestParams(context, FunctionNameFindId.Login_GetToken.getStringValue(), reportReqParam);
            }
            Observable.error(ExceptionUtil.defaultException(e));
        }
        requestEntity = HttpInjectUtils.injectHttp(getClass(), "pinReauthenticationForNoPin", requestEntity, AuthTokenRequestEntity.class);
        SparseArray<String> reseponseData = getDatas(requestEntity);
        if (reseponseData != null && reseponseData.size() != 0) {
            int responseCode = -1;
//            for (Integer key : reseponseData.keySet()) {
//                responseCode = key;
//                break;
//            }
            for (int i = 0; i < reseponseData.size(); i++) {
                responseCode = reseponseData.keyAt(i);
                break;
            }
            if (responseCode != 200 && responseCode != 202) {
                CommonError commonError = GsonHelper.fromJson(reseponseData.get(responseCode), CommonError.class);
                if (entity.isAutoLogin()) {
                    isSuccess = false;
                    long endTimeStamp = System.currentTimeMillis();
                    ReportReqParam reportReqParam = ReportReqParam.getLoginReqParm(isSuccess);
                    reportReqParam.startTimestamp = startTimeStamp;
                    reportReqParam.endTimestamp = endTimeStamp;
                    reportReqParam.functionNameFindId = FunctionNameFindId.Login_GetToken.getStringValue();
                    BusinessUtil.sendReportByRequestParams(context, FunctionNameFindId.Login_GetToken.getStringValue(), reportReqParam);
                }
                throw new HttpException(commonError.getErrorCode(), commonError.getErrorMessage());
            } else {
                //成功请求
                try {
                    String response = AuthUtils.decodeJwtToJson(reseponseData.get(responseCode));
                    log.d(">>>>>>>>>>>>>>>>>>>>>>>>>authorize pinReauthentication for no pin success<<<<<<<<<<<<<<<<<<<<<<"
                            + response);
                    AuthPinTokenEntity pinTokenEntity = GsonHelper.fromJson(response, AuthPinTokenEntity.class);
                    ApplicationUtil.getInstance().updateToken(pinTokenEntity.getTokenType(), pinTokenEntity.getAccessToken());
                    // update the time when get the token
                    // saveTokenInPreference
                    PreferencesUtls.getInstance(context).putString(Constants.TIME_LOCAL_TOKEN,
                            System.currentTimeMillis() + "");
                    PreferencesUtls.getInstance(context).putString(Constants.ACCESS_TOKEN,
                            Constants.ACCESS_TOKEN_NORMAL + "@" + pinTokenEntity.getTokenType() + " " + pinTokenEntity.getAccessToken());
                    log.d("token time" + PreferencesUtls.getInstance(context).getString(Constants.TIME_LOCAL_TOKEN));
                    if (!CommonUtil.isNull(pinTokenEntity.getIdToken())) {
                        PreferencesUtls.getInstance(context).putString(Constants.ID_TOKEN, pinTokenEntity.getIdToken());
                        PreferencesUtls.getInstance(context).putString(Constants.TIME_ID_TOKEN,
                                System.currentTimeMillis() + "");
                        return pinTokenEntity;
                    }
                    if (entity.isAutoLogin()) {
                        isSuccess = true;
                        long endTimeStamp = System.currentTimeMillis();
                        ReportReqParam reportReqParam = ReportReqParam.getLoginReqParm(isSuccess);
                        reportReqParam.startTimestamp = startTimeStamp;
                        reportReqParam.endTimestamp = endTimeStamp;
                        reportReqParam.functionNameFindId = FunctionNameFindId.Login_GetToken.getStringValue();

                        BusinessUtil.sendReportByRequestParams(context, FunctionNameFindId.Login_GetToken.getStringValue(), reportReqParam);
                    }
                } catch (Exception e) {
                    log.e("authorize pinReauthentication failure for no pin: " + e.getMessage());
                    if (!AuthorUtil.getInstance().isLoginOut) {
                        AuthorUtil.getInstance().loginOut(context);
                    }
                    if (entity.isAutoLogin()) {
                        isSuccess = false;
                        long endTimeStamp = System.currentTimeMillis();
                        ReportReqParam reportReqParam = ReportReqParam.getLoginReqParm(isSuccess);
                        reportReqParam.startTimestamp = startTimeStamp;
                        reportReqParam.endTimestamp = endTimeStamp;
                        reportReqParam.functionNameFindId = FunctionNameFindId.Login_GetToken.getStringValue();

                        BusinessUtil.sendReportByRequestParams(context, FunctionNameFindId.Login_GetToken.getStringValue(), reportReqParam);
                    }
                    throw ExceptionUtil.defaultException(e);
                }
            }
        }
        return null;
    }

    public Observable<AuthPinTokenEntity> pinReauth(final AuthTokenRequestEntity entity) {
        return Observable.defer(new Func0<Observable<AuthPinTokenEntity>>() {
            @Override
            public Observable<AuthPinTokenEntity> call() {
                try {
                    return Observable.just(pinReauthentication(entity));
                } catch (OnStarException e) {
                    return Observable.error(e);
                }
            }
        });
    }

    /**
     * @Title: pinReauthentication @Description: PIN auth, @param 设定文件 @return
     * void 返回类型 @throws
     */
    @Request(heads = @HeadsValue(accept = HttpAccept.JSON, language = Language.AUTO), method = HttpMethod.POST)
    public AuthPinTokenEntity pinReauthentication(AuthTokenRequestEntity entity) throws OnStarException {
        entity.setDeviceId(new DeviceUtil(context).getDeviceID());
        OauthService service = new OauthService(Constants.CURRENT_AUTH_URL);
        RequestEntity requestEntity = NetConnectUtil.getAuthRequestEntity(context);
        String idToken = PreferencesUtls.getInstance(context).getString(Constants.ID_TOKEN);
        try {
            requestEntity = service.authPinToken(requestEntity, entity.getClientId(), idToken, entity.getDeviceId(),
                    entity.getClientSecret(), entity.getPin(), entity.getScope());
        } catch (Exception e1) {
            log.e("authorize pinReauthentication failure : " + e1.getMessage());
            AuthorUtil.getInstance().loginOut(context);
            throw ExceptionUtil.defaultException(e1);
        }
        try {
            String requestbody = AuthUtils.decodeJwtToJson(requestEntity.getBody());
            log.d(">>>>>>>>>>>>>>>>>>>authorize pinReauthentication success<<<<<<<<<<<<<<<<<<<<" + requestbody);
        } catch (Exception e) {
            AuthorUtil.getInstance().loginOut(context);
            log.d(">>>>>>>>>>>>>>>>>>>authorize pinReauthentication success<<<<<<<<<<<<<<<<<<<<" + e.getMessage());
            throw ExceptionUtil.defaultException(e);
        }

        requestEntity = HttpInjectUtils.injectHttp(getClass(), "pinReauthentication", requestEntity, AuthTokenRequestEntity.class);
        SparseArray<String> reseponseData = getDatas(requestEntity);
        if (reseponseData != null && reseponseData.size() != 0) {
            int responseCode = -1;
//            for (Integer key : reseponseData.keySet()) {
//                responseCode = key;
//                break;
//            }
            for (int i = 0; i < reseponseData.size(); i++) {
                responseCode = reseponseData.keyAt(i);
                break;
            }
            if (responseCode != 200 && responseCode != 202) {
                CommonError commonError = GsonHelper.fromJson(reseponseData.get(responseCode), CommonError.class);
                throw new HttpException(commonError.getErrorCode(), commonError.getErrorMessage());
            } else {
                //成功请求
                try {
                    String response = AuthUtils.decodeJwtToJson(reseponseData.get(responseCode));
                    AuthPinTokenEntity pinTokenEntity = GsonHelper.fromJson(response, AuthPinTokenEntity.class);
                    ApplicationUtil.getInstance().updateToken(pinTokenEntity.getTokenType(), pinTokenEntity.getAccessToken());
                    // update the time when get the token
                    PreferencesUtls.getInstance(context).putString(Constants.TIME_LOCAL_TOKEN,
                            System.currentTimeMillis() + "");
                    log.d("token time is--> "
                            + PreferencesUtls.getInstance(context).getString(Constants.TIME_LOCAL_TOKEN));
                    if (!CommonUtil.isNull(pinTokenEntity.getIdToken())) {
                        PreferencesUtls.getInstance(context).putString(Constants.ID_TOKEN, pinTokenEntity.getIdToken());
                        PreferencesUtls.getInstance(context).putString(Constants.TIME_ID_TOKEN,
                                System.currentTimeMillis() + "");
                    }
                    PreferencesUtls.getInstance(context).putString(Constants.ACCESS_TOKEN,
                            Constants.ACCESS_TOKEN_HIGH + "@" + pinTokenEntity.getTokenType() + " " + pinTokenEntity.getAccessToken());
                    log.d("authorize pinReauthentication  success the token is ------------------->"
                            + pinTokenEntity.getTokenType() + " " + pinTokenEntity.getAccessToken());

                    AuthorUtil.getInstance().cancelRegistAlarmReauthentication(context);
                    AuthorUtil.getInstance().registAlarmReauthentication(context);
                    return pinTokenEntity;
                } catch (Exception e) {
                    log.e("authorize pinReauthentication failure : " + e.getMessage());
                    AuthorUtil.getInstance().loginOut(context);
                    throw ExceptionUtil.defaultException(e);
                }
            }
        }
        return null;
    }


    public Observable<String> doUpgrade(final AuthTokenRequestEntity entity) {
        return Observable.defer(new Func0<Observable<String>>() {
            @Override
            public Observable<String> call() {
                try {
                    return Observable.just(upgrade(entity));
                } catch (OnStarException e) {
                    return Observable.error(e);
                }
            }
        });
    }

    /**
     * @Title: upgrade @Description: Upgrade accessToken and update application
     * accessToken @param 设定文件 @return void 返回类型 @throws
     */
    @Request(heads = @HeadsValue(accept = HttpAccept.JSON, language = Language.AUTO), method = HttpMethod.POST)
    public String upgrade(AuthTokenRequestEntity entity) throws OnStarException {
        entity.setDeviceId(new DeviceUtil(context).getDeviceID());
        OauthService service = new OauthService(Constants.CURRENT_AUTH_URL);
        RequestEntity requestEntity = NetConnectUtil.getAuthRequestEntity(context);
        try {
            requestEntity = service.upgrade(requestEntity, entity.getClientId(), entity.getDeviceId(),
                    entity.getClientSecret(), entity.getPin());
        } catch (Exception e1) {
            log.e("authorize upgrade failure" + e1.getMessage());
            throw ExceptionUtil.defaultException(e1);
        }

        PreferencesUtls.getInstance(context).putString(Constants.ACCESS_TOKEN,
                Constants.ACCESS_TOKEN_HIGH + "@" + ApplicationUtil.getInstance().getToken());

        requestEntity = HttpInjectUtils.injectHttp(getClass(), "upgrade", requestEntity, AuthTokenRequestEntity.class);
        SparseArray<String> reseponseData = getDatas(requestEntity);
        if (reseponseData != null && reseponseData.size() != 0) {
            int responseCode = -1;
//            for (Integer key : reseponseData.keySet()) {
//                responseCode = key;
//                break;
//            }
            for (int i = 0; i < reseponseData.size(); i++) {
                responseCode = reseponseData.keyAt(i);
                break;
            }
            if (responseCode != 200 && responseCode != 202) {
                CommonError commonError = GsonHelper.fromJson(reseponseData.get(responseCode), CommonError.class);
                throw new HttpException(commonError.getErrorCode(), commonError.getErrorMessage());
            } else {
                return "";
            }
        }
        return null;
    }
}
